package com.um.springboot.starter.service.impl;

import com.um.springboot.starter.dao.ColumnUtil;
import com.um.springboot.starter.dao.CommonDao;
import com.um.springboot.starter.entity.Page;
import com.um.springboot.starter.helper.SessionHelper;
import com.um.springboot.starter.properties.HshProperties;
import com.um.springboot.starter.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ResourceUtils;

import java.util.*;

/**
 * @author 邓南辉
 * @date 2019/12/9
 * @copyright 广州优匠科技有限公司
 */
@Slf4j
@Service
public class BaseService {

    @Autowired
    protected CommonDao dao;

    @Autowired
    protected HshProperties hshProperties;

    @Autowired
    protected SessionHelper sessionHelper;

    /**
     * 获得当前用户所在公司ID
     * @return
     */
    public String getComId(){
        return dao.getComId();
    }


    protected Page parsePage(Map map){
        int start = Integer.parseInt(map.get("start")+"");
        int limit = Integer.parseInt(map.get("limit")+"");
        Page page = new Page();
        page.setPageNo(start);
        page.setPageSize(limit);
        return page;
    }

    ///////////////////////////////保存操作///////////////////////////////////

    /**
     * 添加记录，饶开框架，不做历史记录
     */
    public boolean saveRecord(String tableName,Map entity){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        if(entity.containsKey(primaryKey)){
            return dao.updateRecord(tableName, entity);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            entity.put(primaryKey, id);
            return dao.addRecord(tableName, entity);
        }
    }

    /**
     * 添加记录，饶开框架，不做历史记录
     */
    public boolean addRecord(String tableName,Map entity){
        return dao.addRecord(tableName, entity);
    }

    /**
     * 修改记录，饶开框架，不做历史记录
     */
    public boolean updateRecord(String tableName,Map entity){
        return dao.updateRecord(tableName, entity);
    }


    /**
     * 特殊业务使用：保存记录，饶开框架，不做历史记录
     */
    public boolean saveRow(String tableName,Map entity){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        if(entity.containsKey(primaryKey) && !StringUtil.getTrim(entity.get(primaryKey)).equals("")){
            return dao.updateRow(tableName, entity);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            entity.put(primaryKey, id);
            return dao.addRow(tableName, entity);
        }
    }

    /**
     * 特殊业务使用：添加记录，饶开框架，不做历史记录
     */
    public boolean addRow(String tableName,Map entity){
        return dao.addRow(tableName, entity);
    }

    /**
     * 特殊业务使用：修改记录
     */
    public boolean updateRow(String tableName,Map entity){
        return dao.updateRow(tableName, entity);
    }

    /**
     * 查询一个实体(内部使用，service不要使用)，饶开框架，不做历史记录
     * @param tableName 表名
     * @param properties 属性名数组
     * @param values 属性值数组
     * @return 返回一个对象Map
     */
    public Map queryRow(String tableName,Object[] properties,Object[] values){
        return dao.queryRow(tableName,properties,values);
    }

    /**
     * 查询一个列表(内部使用，service不要使用)，饶开框架，不做历史记录
     * @param tableName 表名
     * @param properties 属性名数组
     * @param values 属性值数组
     * @return 返回一个对象List
     */
    public List queryRows(String tableName,Object[] properties,Object[] values){
        return dao.queryRows(tableName,properties,values);
    }

    /**
     * 保存一个对象,如果对象存在就更新，不存在就插入
     * @param tableName 表名
     * @param map 属性和值
     * @return 执行成功返回true
     */
    public boolean save(String tableName,Map<String,Object> map){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        if(map.containsKey(primaryKey)){
            return dao.update(tableName, map);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            return dao.add(tableName, map);
        }
    }

    /**
     * 同时保存多个对象
     * @param mapTable key和value都是表名的Map
     * @param mapValue key为表名， value为实体对象的Map
     * @return 执行成功返回true
     */
    public boolean saveCommand(Map<String,String> mapTable,Map<String,Map<String,Object>> mapValue){
        Iterator<String> it = mapTable.keySet().iterator();
        while(it.hasNext()){
            String key = (String)it.next();
            save(mapTable.get(key),mapValue.get(key));
        }
        return true;
    }


    /**
     * 保存一个对象,如果对象存在就更新，不存在就插入
     * @param tableName 表名
     * @param map 属性和值
     * @return 返回保存后的实体Map
     */
    public Map<String,Object> saveEntity(String tableName,Map<String,Object> map){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        if(map.containsKey(primaryKey)){
            dao.update(tableName, map);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            dao.add(tableName, map);
        }
        return map;
    }

    /**
     * 保存一个对象,如果对象存在就更新，不存在就插入
     * @param tableName 表名
     * @param map 属性和值
     * @param properties 额外添加的属性，类型geometry专用
     * @param values 额外添加的值
     * @return 返回保存后的实体Map
     */
    public Map<String,Object> saveEntity(String tableName,Map<String,Object> map,String[] properties,String[] values){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        if(map.containsKey(primaryKey)){
            dao.update(tableName, map,properties,values);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            dao.add(tableName, map,properties,values);
        }
        return map;
    }

    /**
     * 保存一个对象,并且会比code列自动编号,表中一定要有parent_code列,如果对象存在就更新，不存在就插入
     * @param tableName 表名
     * @param map 属性和值
     */
    public boolean saveCodeEntity(String tableName,Map<String,Object> map){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        if(map.containsKey(primaryKey)){
            return dao.update(tableName, map);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            String parentCode = map.get("parent_code").toString();
            String code = dao.getMaxCode(tableName, "code", "parent_code", parentCode, 4);
            map.put("code", code);
            return dao.add(tableName, map);
        }
    }

    /**
     * 保存移动树节点对象,重新生成code并修改所有子节点code
     * @param tableName
     * @param map
     * @return
     */
    public boolean saveMoveCodeEntity(String tableName,Map<String,Object> map){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);

        String parentCode = map.get("parent_code").toString();
        String code = dao.getMaxCode(tableName, "code", "parent_code", parentCode, 4); //新生成code
        String initialCode = map.get("code").toString(); //原始code

        List<Map<String,Object>> nodeList = dao.queryLikeList(tableName,new String[]{"parent_code"},new String[]{initialCode+"%"});
        for(Map node : nodeList){
            String nodeCode = code + StringUtil.getTrim(node.get("code")).substring(initialCode.length());
            node.put("parent_code",code);
            node.put("code",nodeCode);
            dao.update(tableName,node);
        }

        map.put("code", code);

        if(map.containsKey(primaryKey)){
            return dao.update(tableName, map);
        }else{
            String id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            return dao.add(tableName, map);
        }
    }





    /**
     * 保存一个主表对象和子表的多个对象
     * @param tableName 主表名
     * @param map 主对象
     * @param subTableName 子表名
     * @param subList 子表对象列表
     */
    public boolean saveAndSubList(String tableName, Map<String,Object> map, String subTableName, List<Map<String,Object>> subList){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        String id = null;
        boolean result = true;
        if(map.containsKey(primaryKey)){
            id = map.get(primaryKey).toString();
            dao.deleteTrue(subTableName, ColumnUtil.getPrimaryKey(tableName), id);
            dao.update(tableName, map);
        }else{
            id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            dao.add(tableName, map);
        }
        for(Map<String,Object> subMap : subList){
            subMap.remove(ColumnUtil.getPrimaryKey(subTableName));
            subMap.put(ColumnUtil.getPrimaryKey(tableName), id);
            save(subTableName, subMap);
        }
        return result;
    }

    /**
     * 保存一个对象和中间表的关系
     * @param tableName 主表名
     * @param map 主对象
     * @param otherTableName 另外个主表名
     * @param midTableName 中间表列表
     * @param subList 关系ID列表
     */
    public boolean saveAndMiddle(String tableName,Map<String,Object> map,String otherTableName,String midTableName,List<Object> subList){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        String otherPrimaryKey = ColumnUtil.getPrimaryKey(otherTableName);
        String id = null;
        boolean result = true;
        if(map.containsKey(primaryKey)){
            result = result && dao.update(tableName, map);
            id = map.get(primaryKey).toString();
            //删除关系表数据
            dao.deleteTrue(midTableName, primaryKey, id);
        }else{
            id = UUID.randomUUID().toString().replaceAll("-", "");
            map.put(primaryKey, id);
            result = result && dao.add(tableName, map);
        }
        //添加关系表数据
        for(Object subId : subList){
            Map<String,Object> subMap = new Hashtable<String,Object>();
            if(subId==null || subId.equals(""))
                continue;
            subMap.put(primaryKey, id);
            subMap.put(otherPrimaryKey, subId);
            result = result && dao.add(midTableName,subMap);
        }
        return result;
    }

    /**
     * 保存多个对象列表
     * @param tableName 表名
     * @param list 对象列表
     */
    public boolean saveList(String tableName,List<Map<String,Object>> list){
        String primaryKey = ColumnUtil.getPrimaryKey(tableName);
        boolean result = true;
        for(Map<String,Object> map : list){
            if(map.containsKey(primaryKey)){
                dao.update(tableName, map);
            }else{
                String id = UUID.randomUUID().toString().replaceAll("-", "");
                map.put(primaryKey, id);
                result = result && dao.add(tableName, map);
            }
        }
        return result;
    }

    /**
     * 更改一个对象
     * @param tableName 表名
     * @param map 实体Map
     */
    public boolean update(String tableName,Map<String,Object> map){
        return dao.update(tableName, map);
    }



    /**
     * 根据主键删除表
     * @param tableName 表名
     * @param id 表主键ID
     * @return 执行成功返回true
     */
    public boolean delete(String tableName,String id){
        return dao.delete(tableName, id);
    }

    /**
     * 删除一个列表
     * @param tableName 表名
     * @param list 主键ID列表
     * @return 执行成功返回true
     */
    public boolean delete(String tableName,List<String> list){
        return dao.delete(tableName, list);
    }

    /**
     * 删除多个主表对象及对应关系子表
     * @param tableName 主表名
     * @param foreignTable 外键表名
     * @param idList 主表ID列表
     * @return 执行成功返回true
     */
    public boolean deleteListAndForeign(String tableName,String foreignTable,List<Object> idList){
        return dao.delete(tableName, foreignTable,idList);
    }


    /**
     * 根据指定属性删除对象
     * @param tableName 表名
     * @param properties 属性数组
     * @param values 值数组
     * @return 执行成功返回true
     */
    public boolean deleteByProperties(String tableName, String[] properties,Object[] values) {
        return dao.delete(tableName, properties, values);
    }

    /**
     * 根据一个属性删除对象
     * @param tableName 表名
     * @param property 属性名
     * @param value 值
     * @return 执行成功返回true
     */
    public boolean delete(String tableName, String property, Object value) {
        return dao.delete(tableName, property,value);
    }


    /**
     * 递归逻辑删除一个树桔构的记录以及它的所有子节点
     * @param tableName 表名
     * @param list 主键ID列表
     * @param parentColumn 父节点列名
     * @return 执行成功返回true
     */
    @SuppressWarnings("unchecked")
    public boolean deleteNode(String tableName,List<String> list ,String parentColumn){
        return dao.deleteNode(tableName,list,parentColumn);
    }


    /**
     * 根据多个属性查询指定列表
     * @param tableName 表名
     * @param properties 属性名称
     * @param values 属性值
     * @param orderNames 排序字段数组
     * @param sortOns 降序或升序数组
     * @return 返回一个列表
     */
    public List queryList(String tableName,String[] properties,Object[] values,Object[] orderNames,Object[] sortOns) {
        return dao.queryList(tableName, properties, values, orderNames, sortOns);
    }

    /**
     * 根据多个属性查询指定列表
     * @param tableName 表名
     * @param properties 属性名称
     * @param values 属性值
     * @return 返回一个列表
     */
    public List queryList(String tableName,Object[] properties,Object[] values) {
        return dao.queryList(tableName, properties, values);
    }

    /**
     * 通过分页条件查询列表
     * @param tableName 表名称
     * @param columns 查询列名
     * @param map 查询条件
     * @param custom 自定义条件
     * @return
     */
    public List queryList(String tableName,Object[] columns,Map map,Map custom) {
        return dao.queryList(tableName, columns, map, custom);
    }

    /**
     * 通过分页条件查询列表
     * @param tableName 表名称
     * @param columns 查询列名
     * @param map 查询条件
     * @param custom 自定义条件
     * @param start start
     * @param limit limit
     * @return
     */
    public List queryList(String tableName,Object[] columns,Map map,Map custom,int start, int limit) {
        return dao.queryList(tableName, columns, map, custom, start, limit);
    }

    /**
     * 根据多个属性查询指定属性的列表
     * @param tableName 表名
     * @param ignoreCcolumns 查询指 定忽略的列名
     * @param properties 属性名称
     * @param values 属性值
     * @param orderNames 排序字段
     * @param sortOns 降序或升序
     * @return 返回一个列表
     */
    public List queryListIgnore(String tableName,Object[] ignoreCcolumns,Object[] properties,Object[] values,String[] orderNames,String[] sortOns,String oper) {
        return dao.queryIgnore(tableName, ignoreCcolumns, properties, values, orderNames, sortOns, oper);
    }

    //////////////////////////////////////////////////////// like 操作////////////////////////////////////////////////////////
    /**
     * 根据多个属性查询指定列表
     * @param tableName 表名
     * @param properties 属性名称数组
     * @param values 属性值数组
     * @param orderNames 排序字段数组
     * @param sortOns 降序或升序数组
     * @return 返回一个列表
     */
    public List queryLikeList(String tableName,String[] properties,Object[] values,Object[] orderNames,Object[] sortOns) {
        return dao.queryLikeList(tableName, properties, values, orderNames, sortOns);
    }

    ///////////////////////////////////////查询一个对象 map///////////////////////////////////////////////////
    /**
     * 查询一个对象
     * @param tableName 表名
     * @param columns 指定查询对象的哪些属性
     * @param properties 查询属性数组
     * @param values 查询属性值数组
     * @return 返回一个对象
     */
    public Map queryEntity(String tableName,String[] columns, Object[] properties,Object[] values) {
        return dao.queryMap(tableName, columns, properties, values);
    }

    /**
     * 查询一个对象
     * @param tableName 表名
     * @param property 查询属性
     * @param value 查询属性值
     * @return 返回一个对象
     */
    public Map queryEntity(String tableName, String property,Object value) {
        return dao.queryMap(tableName, property, value);
    }

    /**
     * 根据主键ID查询一个对象
     * @param tableName 表名
     * @param id 主键ID
     * @return 返回一个对象
     */
    public Map queryEntity(String tableName,Object id) {
        return dao.queryMap(tableName,id);
    }

    /**
     * 查询一个对象
     * @param tableName 表名
     * @param properties 查询属性数组
     * @param values 查询属性值数组
     * @return 返回一个对象
     */
    public Map queryEntity(String tableName, String[] properties,String[] values) {
        return dao.queryMap(tableName, new String[]{}, properties, values);
    }


    /**
     * 根据属性查询行数
     * @param tableName 表名
     * @param properties 查询属性数组
     * @param values 查询属性值数组
     * @return 返回一个整数
     */
    public long queryCountByProperties(String tableName,String[] properties,Object[] values){
        return dao.queryCount(tableName, properties, values, "=");
    }


    /**
     * 根据SQL查询行数
     * @param sql SQL语句
     * @param list SQL参数列表
     * @return 返回一个整数
     */
    public long queryCountBySQL(String sql,Object[] list){
        return dao.queryCountBySQL(sql,list);
    }

    /**
     *
     * @param sqlName
     * @param values
     * @return
     */
    public List queryListBySQLName(String sqlName,Object[] values){
        return dao.queryListBySQLName(sqlName,values);
    }

    /**
     * 根据sql查询一个列表
     * @param sql SQL语句
     * @param values SQL语句的参数值
     * @return 返回一个List
     */
    @SuppressWarnings("unchecked")
    public List queryListBySQL(String sql,Object[] values){
        return dao.queryListBySQL(sql,values);
    }

    /**
     * 自定义条件分页查询指定字段
     * @param tableName 表名称
     * @param page 分页对象
     * @param columns 查询列名
     * @param map 查询条件
     * @param custom 自定义条件
     * @return 返回一个Page对象
     */
    public Page queryPageByCustom(String tableName, Page page, String[] columns, Map map, Map custom) {
        return dao.queryPage(tableName, page, columns, map, custom);
    }

    /**
     * 分页查询
     * @param tableName 表名称
     * @param page 分页对象
     * @param map 查询条件
     * @return 返回一个Page对象
     */
    public Page queryPage(String tableName,Page page,Map map){
        return dao.queryPage(tableName,page,new String[]{},map,new Hashtable());
    }

    /**
     *
     * @param tableName
     * @param page
     * @param columns
     * @param map
     * @param custom
     * @return
     */
    public Page queryPage(String tableName, Page page,Object[] columns,Map map,Map custom){
        return dao.queryPage(tableName,page,columns,map,custom);
    }

    /**
     * SQL分页查询
     * @param page 分页对象
     * @param sql SQL语句
     * @param sumSQL 查询总数的SQL语句
     * @param list SQL语句参数
     * @return 返回一个Page对象
     */
    public Page queryPageSQL(Page page,String sql,String sumSQL,List<Object> list){
        return dao.queryPageSQL(page,sql,sumSQL,list);
    }

    /**
     * 根据SQL分页查询
     * @param page 分页的对象
     * @param sql  查询分页的SQL语句
     * @param sumSQL 查询总数的SQL语句
     * @param listSQL 查询列表条件参数
     * @param listSUM 查询总条数条件参数
     * @return 返回page对象
     */
    @SuppressWarnings("unchecked")
    public Page queryPageSQL(Page page,String sql,String sumSQL,List<Object> listSQL,List<Object> listSUM){
        return dao.queryPageSQL(page,sql,sumSQL,listSQL,listSUM);
    }

    /**
     * 根据SQL名称分页查询
     * @param page 分页的对象
     * @param sqlName 查询分页的SQL名称
     * @param sumSqlName 查询总数的SQL名称
     * @param map 查询条件
     * @param custom 自定义条件
     * @return 返回page对象
     */
    @SuppressWarnings("unchecked")
    public Page querySQLPage(Page page,String sqlName,String sumSqlName,Map map,Map custom){
        return dao.querySQLPage(page,sqlName,sumSqlName,map,custom);
    }

    /**
     * 根据SQL名称分页查询
     * @param page 分页的对象
     * @param sqlName 查询分页的SQL名称
     * @param sumSqlName 查询总数的SQL名称
     * @param list SQL的查询条件参数
     * @return 返回page对象
     */
    @SuppressWarnings("unchecked")
    public Page querySQLPageValues(Page page,String sqlName,String sumSqlName,Map map,Map custom,List list){
        return dao.querySQLPageValues(page,sqlName,sumSqlName,map,custom,list);
    }

    /**
     * SQL分页查询
     * @param page 分页对象
     * @param sqlName SQL语句名称
     * @param sumSQLName 查询总数的SQL语句名称
     * @param list SQL语句参数
     * @return 返回一个Page对象
     */
    public Page queryPageSQLName(Page page, String sqlName, String sumSQLName, List<Object> list){
        return dao.queryPageSQLName(page,sqlName,sumSQLName,list);
    }

    /**
     * 根据SQL名称分页查询
     * @param page 分页的对象
     * @param sqlName 查询分页的SQL名称
     * @param sumSqlName 查询总数的SQL名称
     * @param listSQL 列表查询条件参数
     * @param listSUM 总条数查询条件参数
     * @return 返回page对象
     */
    @SuppressWarnings("unchecked")
    public Page queryPageSQLName(Page page,String sqlName,String sumSqlName,List<Object> listSQL,List<Object> listSUM){
        return dao.queryPageSQLName(page,sqlName,sumSqlName,listSQL,listSUM);
    }


    /**
     * 根据多个属性查询指定列表的前几条数据
     * @param tableName 表名
     * @param properties 属性名称
     * @param values 属性值
     * @param orderName 排序字段
     * @param sortOn 降序或升序
     * @param num 返回list的大小
     * @return 返回指定大小的list
     */
    public List queryNum(String tableName, Object[] properties, Object[] values, String orderName, String sortOn, int num) {
        return dao.queryNum(tableName, properties, values, new Object[]{orderName}, new Object[]{sortOn},num);
    }

    /**
     * 获得导出文件路径，兼容jar打包方式和war打包方式
     * @param fileName 导出的文件名称
     * @return
     */
    protected String getExportFilePath(String fileName){
        String path = "";
        try{
            if(hshProperties.getConfig().getPackaging().equals("jar") || !hshProperties.getFile().isRelative()){
                path = hshProperties.getFile().getPath()+"/export/"+fileName;
            }else{
                path = ResourceUtils.getURL("classpath:").getPath()+"static"+hshProperties.getFile().getPath()+"/export/"+fileName;
            }
        }catch (Exception ex){
            log.error("", ex);
        }
        return path;
    }

    /**
     * 返回文件的绝对路径
     * @param path 目录名称
     * @param fileName 文件名称
     * @return
     */
    protected String getFilePath(String path,String fileName){
        String filePath = "";
        try{
            if(hshProperties.getConfig().getPackaging().equals("jar") || !hshProperties.getFile().isRelative()){
                filePath = hshProperties.getFile().getPath()+"/"+path+"/"+fileName;
            }else{
                filePath = ResourceUtils.getURL("classpath:").getPath()+"static"+hshProperties.getFile().getPath()+"/"+path+"/"+fileName;
            }
        }catch (Exception ex){
            log.error("", ex);
        }
        return filePath;
    }

    /**
     * 返回文件的绝对路径
     * @param path 文件路径
     * @return
     */
    protected String getFilePath(String path){
        String filePath = "";
        try{
            if(hshProperties.getConfig().getPackaging().equals("jar") || !hshProperties.getFile().isRelative()){
                filePath = hshProperties.getFile().getPath()+"/"+path;
                log.debug("filePath0:"+filePath);
            }else{
                filePath = ResourceUtils.getURL("classpath:").getPath()+"static"+hshProperties.getFile().getPath()+"/"+path;
                log.debug("filePath1:"+filePath);
            }
        }catch (Exception ex){
            log.error("", ex);
        }
        return filePath;
    }

}
